home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Graphics 2D / CustomPicComments / CustomPC⁄B.c < prev    next >
Encoding:
Text File  |  2000-09-28  |  21.5 KB  |  695 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        CustomPC/B.c
  3.  
  4.     Contains:    Sample showing how to implement custom PicComments and QuickDraw bottlenecks. 
  5.                 See the ReadMe for code details.
  6.  
  7.     Written by:     
  8.  
  9.     Copyright:    Copyright © 1991-1999 by Apple Computer, Inc., All Rights Reserved.
  10.  
  11.                 You may incorporate this Apple sample source code into your program(s) without
  12.                 restriction. This Apple sample source code has been provided "AS IS" and the
  13.                 responsibility for its operation is yours. You are not permitted to redistribute
  14.                 this Apple sample source code as "Apple sample source code" after having made
  15.                 changes. If you're going to re-distribute the source, we require that you make
  16.                 it clear in the source that the code was descended from Apple sample source
  17.                 code, but that you've made changes.
  18.  
  19.     Change History (most recent first):
  20.                 08/2000            JM        Carbonized, non-Carbon code is commented out
  21.                                         for demonstration purposes.
  22.                 7/9/1999        KG        Updated for Metrowerks Codewarror Pro 2.1
  23.                 03/97    v. 2.0    ik        Rewritten as 'Custom PicComments/Bottlenecks'
  24.                 10/91    v. 1.0    dh        Shipped as 'DTS Groupies' sample.
  25.                 
  26.  
  27. */
  28. #include "CarbonPrefix.h"
  29. #include <Dialogs.h>
  30. #include <Fonts.h>
  31. #include <Menus.h>
  32. #include <Devices.h>
  33. #include <Resources.h>
  34.  
  35. /*------ constants --------------------------------------------------------------------------*/
  36.  
  37.  
  38. #define kCreatorType    'EGAD'        /* Our creator type.                */
  39.  
  40. #define rMenuBar        128            /* The menubar resource ID.            */
  41. #define mApple            128            /* Apple menu ID.                    */
  42. #define iAbout            1            /* "About…" menu item index.        */
  43. #define mFile            129            /* File menu ID.                    */
  44. #define iQuit            1            /* Quit menu item index.            */
  45.  
  46. #define kMaxPICTs        50            /* Max. no. of pictures we handle.    */
  47. #define kCustomComment    100            /* Custom PicComment indicator.        */
  48. #define kSubPICTComment    200            /* Our (sub-picture) sub-PicComment.
  49.                                        This comment indicates that we've
  50.                                        stored a picture inside of a
  51.                                        picture.  We use it to extract
  52.                                        the individual PICTs.            */
  53.  
  54. /*------ types --------------------------------------------------------------------------*/
  55.  
  56.  
  57. typedef struct TPICTRec {
  58.     int            numPICTs;            /* The number of sub-pictures,         */
  59.     PicHandle    picture[kMaxPICTs];    /* and their PicHandles,            */
  60.     Rect        curPos[kMaxPICTs];    /* and their last drawn positions.    */
  61. } TPICTRec;
  62.  
  63. /*------ globals --------------------------------------------------------------------------*/
  64.  
  65.  
  66. static TPICTRec        gPICTRec;        /* Our global picture record.        */
  67. static Rect            gPictsBounds;    /* The bounds used by our pictures.    */
  68. static Boolean        gQuitting;        /* "Quitting?" flag.                */
  69. static WindowPtr    gTheWindow;        /* Our window's pointer.            */
  70.  
  71.  
  72. /*------ prototypes ------------------------------------------------------------------------*/
  73.  
  74. /*extern void            CompositePictures(void);
  75. //extern pascal void    CustomPicProc(int kind, int dataSize, Handle dataHandle);
  76. extern pascal void  CustomPicProc(short kind, short dataSize, Handle dataHandle)
  77. extern void            DisassemblePictures(void);
  78. extern void            DoMenuCommand(long menuResult);
  79. extern void            EventLoop(void);
  80. extern void            MoveThePicts(Rect *wBounds);
  81. extern void            MakeThePicts(void);
  82. extern void            ShowThePicts(void);*/
  83.  
  84. void            CompositePictures(void);
  85. pascal void     CustomPicProc(short kind, short dataSize, Handle dataHandle);
  86. void            DisassemblePictures(void);
  87. void            DoMenuCommand(long menuResult);
  88. void            EventLoop(void);
  89. void            MoveThePicts(Rect *wBounds);
  90. void            MakeThePicts(void);
  91. void            ShowThePicts(void);
  92.  
  93. /*------ CompositePictures ----------------------------------------------------------------*/
  94. //    CompositePictures groups all of the pictures in the global picture record
  95. //    into one "composite" picture.  It removes all of the old pictures and
  96. //    stores the new one.
  97. /*----------------------------------------------------------------------------------------*/
  98.  
  99. void CompositePictures()
  100. {
  101.     PicHandle    aPICT, groupPICT;
  102.     RgnHandle    oldClip;
  103.     int            idx;
  104.     long        dataSize;
  105.     long        ownerApp;
  106.     short        localPicComment;
  107.  
  108. /*    Save the old clipping region, and set a valid one so our grouped
  109.     picture develops ok.                                                */
  110.  
  111.     oldClip = NewRgn();
  112.     GetClip(oldClip);
  113.     ClipRect(&gPictsBounds);
  114.  
  115.     groupPICT = OpenPicture(&gPictsBounds);
  116.  
  117.  
  118. /*    Create a picture to contain all the other ones, then draw those into
  119.     it, separated by our PicComments.  Kill the individual pictures as
  120.     we go.  Finally, close the composite picture.                        */
  121.  
  122.     ownerApp = kCreatorType;
  123.     localPicComment = kSubPICTComment;
  124.  
  125.     for(idx = 0; idx < gPICTRec.numPICTs; idx++)
  126.     {
  127.         aPICT = gPICTRec.picture[idx];
  128.  
  129.  
  130. /*    We don't just use a single custom PicComment since another app may
  131.     use the same comment and conflicts could result.  (Not in this app,
  132.     but in the real world.)  We add six bytes to the handle and store the
  133.     creator type of the app that made the picture followed by 2 bytes
  134.     for a local PicComment kind within the app.  If we used more than
  135.     one PicComment in this app, this extra information would be
  136.     necessary.                                                            */
  137.  
  138.         dataSize = GetHandleSize((Handle) aPICT) +6;
  139.         SetHandleSize((Handle) aPICT, dataSize);
  140.  
  141.         BlockMove((Ptr) *aPICT, (Ptr) *aPICT +6, dataSize -6);
  142.         BlockMove(&ownerApp, (Ptr) *aPICT, 4);
  143.         BlockMove(&localPicComment, (Ptr) *aPICT +4, 2);
  144.  
  145.         PicComment(kCustomComment, dataSize, (Handle) aPICT);
  146.  
  147. /*    Fix the original PicHandle so that we can draw our picture for apps
  148.     that don't know about our custom comments.                            */
  149.  
  150.         BlockMove((Ptr) *aPICT +6, (Ptr) *aPICT, dataSize -6);
  151.         SetHandleSize((Handle) aPICT, dataSize -6);
  152.         DrawPicture(aPICT, &(*aPICT)->picFrame);
  153.         KillPicture(aPICT);
  154.         gPICTRec.picture[idx] = NULL;
  155.     }
  156.  
  157.     ClosePicture();
  158.  
  159.  
  160. /*    Restore the original clipping region and update our global picture
  161.     record so that we have one consolidated picture, in the first slot.
  162.     We set it's current position to (0, 0, 0, 0) so that we don't waste
  163.     time erasing anything on the first draw.                            */
  164.  
  165.     SetClip(oldClip);
  166.     DisposeRgn(oldClip);
  167.  
  168.     gPICTRec.numPICTs = 1;
  169.     gPICTRec.picture[0] = groupPICT;
  170.     SetRect(&gPICTRec.curPos[0], 0, 0, 0, 0);
  171. }
  172.  
  173.  
  174. /*------ CustomPicProc ----------------------------------------------------------------*/
  175. //        CustomPicProc is our replacement for the port's StdCommentProc.
  176. //         in the global picture record
  177. /*----------------------------------------------------------------------------------------*/
  178.  
  179. //pascal void CustomPicProc(int kind, int dataSize, Handle dataHandle)
  180. pascal void CustomPicProc(short kind, short dataSize, Handle dataHandle)
  181. {
  182.     int            nextNum;
  183.     long        ownerApp;
  184.     short        localPicComment;
  185.     Handle        theHandle;
  186.  
  187. /*    If this is a custom PicComment, see if it's ours.  In this app,
  188.     we know it always will be, but when you import other pictures
  189.     you can't be so sure.                                                */
  190.  
  191.     if (kind == kCustomComment && (gPICTRec.numPICTs < kMaxPICTs))
  192.     {
  193.         if (dataSize < 6) return;                        /* Not ours?    */
  194.         
  195.         BlockMove((Ptr) *dataHandle, &ownerApp, 4);
  196.         BlockMove((Ptr) *dataHandle +4, &localPicComment, 2);
  197.  
  198.         if ((ownerApp != kCreatorType) ||                /* Not ours?    */
  199.             (localPicComment != kSubPICTComment)) return;
  200.  
  201.  
  202. /*    This is indeed our picture comment.  Create a handle for the data we
  203.     found, store it in our global picture record and bump the number of
  204.     pictures we have.  The reason that we clear the picture's curPos
  205.     rect is so that we won't waste time erasing anything the first time
  206.     we enter MoveTheGroupies.                                            */
  207.  
  208.         nextNum = gPICTRec.numPICTs;
  209.         gPICTRec.picture[nextNum] = (PicHandle) dataHandle;
  210.         SetRect(&gPICTRec.curPos[nextNum], 0, 0, 0, 0);
  211.  
  212.  
  213. /*    After we create the handle for the data, we have to remember that
  214.     we have 6 bytes of identifying "garbage" in front of the picture
  215.     data.  To remove that, BlockMove all the picture data to the
  216.     beginning of the handle and reset the handle's size.  This is kind
  217.     of a hassle, but it's really best to store your custom PicComments
  218.     this way.  Otherwise, you may misinterpret someone elses comments
  219.     or cause them to misinterpret yours.                                */
  220.  
  221.         if (HandToHand((Handle *) &gPICTRec.picture[nextNum]) == noErr)
  222.         {
  223.             ++gPICTRec.numPICTs;
  224.             theHandle = (Handle) gPICTRec.picture[nextNum];
  225.             BlockMove((Ptr) *theHandle +6, (Ptr) *theHandle, dataSize -6);
  226.             SetHandleSize(theHandle, dataSize -6);
  227.         }
  228.     }
  229. }
  230.  
  231.  
  232. /*------ DisassemblePictures ----------------------------------------------------------------*/
  233. //    DisassemblePictures ungroups the first picture in the global picture
  234. //    record.  It replaces that picture with new pictures of every picture
  235. //    it contained.  All drawing is done within another "dummy" picture
  236. //    so that nothing draws on the screen. The reason we can't use an empty
  237. //    clipping region to do this is that PicComments will be clipped out along
  238. //    with everything else, and we'd be hosed.  (We need the PicComments!)
  239.     
  240. //    This code is written so that it installs the GrafProcs correctly for
  241. //    both GrafPorts and CGrafPorts.
  242. /*----------------------------------------------------------------------------------------*/
  243.  
  244. void DisassemblePictures()
  245. {
  246.     GrafPtr        curPort;
  247.     //QDProcs        theQDProcs;        /* If we're using a GrafPort…            */
  248.     CQDProcs    theCQDProcs;    /* If we're using a CGrafPort…            */
  249.     PicHandle    dummyPICT;
  250.  
  251. /*    Reset the number of pictures in our global picture record to zero.
  252.     There's actually one picture there at this point (the composite
  253.     one), but we must set this to zero so that our PicComment handler
  254.     stores extracted pictures in the right place.                        */
  255.  
  256.     gPICTRec.numPICTs = 0;
  257.  
  258.  
  259. /*    Get the current port and the standard QDProcs or CQDProcs,
  260.     depending on whether we have a GrafPort or CGrafPort.                */
  261.  
  262.     GetPort(&curPort);
  263.  
  264.     //if (curPort->portBits.rowBytes < 0)                /* CGrafPort…        */
  265.     if (GetPortBitMapForCopyBits(curPort)->rowBytes < 0)
  266.     {
  267.         SetStdCProcs(&theCQDProcs);
  268.         theCQDProcs.commentProc = NewQDCommentProc(CustomPicProc);
  269.         //curPort->grafProcs = (QDProcsPtr) &theCQDProcs;
  270.         SetPortGrafProcs(curPort, &theCQDProcs);
  271.     }
  272.     else                                            /* GrafPort…        */
  273.     {
  274.         /*SetStdProcs(&theQDProcs);
  275.         theQDProcs.commentProc = NewQDCommentProc(CustomPicProc);
  276.         //curPort->grafProcs = (QDProcsPtr) &theQDProcs;
  277.         SetPortGrafProcs(curPort, &theQDProcs);*/
  278.         
  279.     }
  280.  
  281.  
  282. /*    Open our dummy picture and draw into it so that our PicComment
  283.     handler is called to parse the picture.  When finished, close the
  284.     picture, kill it and remove our grafProcs.                            */
  285.  
  286.     dummyPICT = OpenPicture(&(*gPICTRec.picture[0])->picFrame);
  287.     DrawPicture(gPICTRec.picture[0], &(*gPICTRec.picture[0])->picFrame);
  288.     ClosePicture();
  289.     KillPicture(dummyPICT);
  290.  
  291.     //curPort->grafProcs = NULL;
  292.     SetPortGrafProcs(curPort, NULL);
  293. }
  294.  
  295.  
  296. /*------ DoMenuCommand ----------------------------------------------------------------*/
  297. //        DoMenuCommand handles our menu items.
  298. /*----------------------------------------------------------------------------------------*/
  299.  
  300. void DoMenuCommand(long menuResult)
  301. {
  302.     int            menuID, menuItem;
  303.     //Str255        daName;
  304.     /*MenuHandle    theMenu;*/
  305.     //GrafPtr        savePort;
  306.  
  307. /*    Get the menu ID and item ID.            */
  308.  
  309.     menuID = (menuResult >>16) & 0xFFFF;
  310.     menuItem = menuResult & 0xFFFF;
  311.  
  312.  
  313. /*    Do what we're supposed to.                */
  314.  
  315.     switch (menuID)
  316.     {
  317.         case mApple:                        /*    Apple Menu                    */
  318.             switch (menuItem)
  319.             {
  320.                 case iAbout:                /*    -> Handle "About…"            */
  321.                     break;
  322.  
  323.                 default:                    /*    -> The rest are DAs.        */
  324.  
  325.                     /*GetPort(&savePort);
  326.                     GetMenuItemText(GetMenuHandle(mApple), menuItem, daName);
  327.                     OpenDeskAcc((ConstStr255Param)daName);
  328.                     SetPort(savePort);*/
  329.                     break;
  330.             };
  331.  
  332.         case mFile:                            /*    File Menu                    */
  333.             switch (menuItem)
  334.             {
  335.                 case iQuit:
  336.                     gQuitting = true;        /*    -> Quit                        */
  337.                     break;
  338.             }
  339.  
  340.     }
  341.  
  342.     HiliteMenu(0);
  343.  
  344. }
  345.  
  346.  
  347. /*------ EventLoop ----------------------------------------------------------------*/
  348. //        EventLoop is a main event loop.  It calls WaitNextEvent and
  349. //        other nice stuff.  It also makes our pictures assemble, disassemble, 
  350. //        and move about.
  351. /*----------------------------------------------------------------------------------------*/
  352.  
  353. void EventLoop()
  354. {
  355.     EventRecord        theEvent;
  356.     WindowPtr        whichWindow;
  357.     short            partCode;
  358.     Rect            dragRect;
  359.     RgnHandle        grayRgn;
  360.     char            key, time;
  361.     unsigned long    finalTicks;
  362.     Rect            tempRect1;
  363.  
  364.  
  365. /*    Set up the rectangle for where we can drag windows.  Initialize
  366.     our "time-through-the-loop" counter to -1 so that it gets bumped
  367.     to zero on the first pass.  This will enable us assemble the
  368.     grouped picture as we go through the first time.                        */
  369.  
  370.     grayRgn = GetGrayRgn();
  371.     //dragRect = (*grayRgn)->rgnBBox;
  372.     GetRegionBounds(GetGrayRgn(), &dragRect);
  373.     time = -1;
  374.  
  375.  
  376. /*    We have a counter which goes from 0-26 and is incremented each time
  377.     we go through this code. At time = 0, We assemble the grouped image.
  378.     At time = 12, we break all the PICTs out of it.  At time = 27, we
  379.     cycle back to time = 0.  In between these life altering times,
  380.     (at least for groupies), we draw all of our current pictures in
  381.     random places.  This clearly shows whether the PICTs are currently
  382.     grouped or not.  We go through this loop until the user quits.            */
  383.  
  384.     do
  385.     {
  386.         //SetPort(gTheWindow);
  387.         SetPortWindowPort(gTheWindow);
  388.         time = ++time % 27;
  389.     
  390.          if (time == 0)
  391.         {
  392.             CompositePictures();            /*    Group the pictures.                */
  393.             //EraseRect(&(gTheWindow)->portRect);
  394.             EraseRect(GetPortBounds(GetWindowPort(gTheWindow), &tempRect1));
  395.         }
  396.  
  397.          if (time == 12)
  398.         {
  399.             DisassemblePictures();        /*    Ungroup the pictures.            */
  400.             //EraseRect(&(gTheWindow)->portRect);
  401.             EraseRect(GetPortBounds(GetWindowPort(gTheWindow), &tempRect1));
  402.         }
  403.  
  404.  
  405. /*    Move all pictures so we can see their current state.                    */
  406.  
  407.         //MoveThePicts(&(gTheWindow)->portRect);
  408.         MoveThePicts(GetPortBounds(GetWindowPort(gTheWindow), &tempRect1));
  409.  
  410.  
  411. /*    Delay so our graphics don't flash.                                        */
  412.  
  413.         Delay((time < 12)? 40:10, &finalTicks);
  414.     
  415.  
  416. /*    Handle any pending events.                                                */
  417.  
  418.         if (WaitNextEvent(everyEvent, &theEvent, 0, NULL))
  419.             switch (theEvent.what)
  420.             {
  421.                 case mouseDown:                    /*    Handle mouse clicks.    */
  422.                 
  423.                     partCode = FindWindow(theEvent.where, &whichWindow);
  424.  
  425.                     switch (partCode)
  426.                     {
  427.                         case inContent:
  428.                             if (whichWindow != FrontWindow())
  429.                                 SelectWindow(whichWindow);
  430.                             break;
  431.     
  432.                         case inDrag:
  433.                             DragWindow(whichWindow, theEvent.where, &dragRect);
  434.                             break;
  435.     
  436.                         case inMenuBar:
  437.                             DoMenuCommand(MenuSelect(theEvent.where));
  438.     
  439.                         case inSysWindow:
  440.                             //SystemClick(&theEvent, whichWindow);
  441.                             break;
  442.                     }
  443.                     break;
  444.     
  445.                 case updateEvt:                    /*    Handle update events.    */
  446.                         BeginUpdate((WindowPtr) theEvent.message);
  447.                         EndUpdate((WindowPtr) theEvent.message);
  448.                     break;
  449.  
  450.                 case keyDown:                    /*    Handle key presses.        */
  451.                 case autoKey: 
  452.                     key = (char) (theEvent.message & charCodeMask);
  453.                     if (((theEvent.modifiers & cmdKey) != 0) && (theEvent.what == keyDown))
  454.                         DoMenuCommand(MenuKey(key));
  455.                     break;
  456.             }
  457.     }
  458.     while (!gQuitting);
  459. }
  460.  
  461.  
  462. /*------ MoveThePicts ----------------------------------------------------------------*/
  463. //    MoveThePicts moves the current pictures… somewhere randomly.  It
  464. //    first erases all the pictures in descending order.  Then it redraws
  465. //    them in new locations in ascending order. This way we don't wipe out
  466. //    any of the new pictures when the old ones are erased.
  467. /*----------------------------------------------------------------------------------------*/
  468.  
  469. void MoveThePicts(Rect *wBounds)
  470. {
  471.     int        newLeft, newTop, width, height, idx;
  472.     float    maxX, maxY;
  473.     Rect    picFrame, curPos;
  474.  
  475. /*    First erase all pictures in reverse order.  Also, calculate their
  476.     new locations and store those in their curPos fields.                */
  477.  
  478.     for (idx = gPICTRec.numPICTs -1; idx >= 0; idx--)
  479.     {
  480.         curPos = gPICTRec.curPos[idx];
  481.         EraseRect(&curPos);
  482.  
  483.         picFrame = (*gPICTRec.picture[idx])->picFrame;
  484.         width = picFrame.right -picFrame.left;
  485.         height = picFrame.bottom -picFrame.top;
  486.  
  487.  
  488. /*    To calculate new positions, we find the maximum position we can
  489.     have for the picture's top left corner.  Then, we find a random
  490.     point that's bounded by (0, 0) and that maximum.  Finally, we
  491.     set this picture's current position so that it has this point for
  492.     its top left corner.                                                */
  493.  
  494.         maxX = (wBounds->right - wBounds->left) -width;
  495.         maxY = (wBounds->bottom - wBounds->top) -height;
  496.         
  497.         newTop = (((float) Random() +32767)/65534.0) * maxX;
  498.         newLeft = (((float) Random() +32767)/65534.0) * maxY;
  499.     
  500.         curPos.top = newTop;
  501.         curPos.left = newLeft;
  502.         curPos.bottom = newTop +height;
  503.         curPos.right = newLeft +width;
  504.         gPICTRec.curPos[idx] = curPos;
  505.     }
  506.  
  507.  
  508. /*    Now draw all the pictures in their new positions.                    */
  509.  
  510.     for (idx = 0; idx < gPICTRec.numPICTs; idx++)
  511.         DrawPicture(gPICTRec.picture[idx], &gPICTRec.curPos[idx]);
  512. }
  513.  
  514.  
  515. /*------ MakeThePicts ----------------------------------------------------------------*/
  516. //    MakeThePicts creates the pictures that will be grouped.  These can be
  517. //    any QuickDraw pictures.  For this example, I use four pictures; one
  518. //    containing a square, one with a circle, one with a triangle and one
  519. //    with some text.  These are all stored in the global picture record.
  520.     
  521. //    This routine is only called once, to put some pictures into the works to
  522. //    start with.
  523. /*----------------------------------------------------------------------------------------*/
  524.  
  525. void MakeThePicts()
  526. {
  527.     RgnHandle    oldClip;
  528.     PolyHandle    trianglePoly;
  529.     int            fNum, vPos;
  530.  
  531. /*    Save the current clipping region so that we can restore it later.
  532.     Set our own clipping region, so that we know we have a valid one.
  533.     Also initialize the number of pictures in our global picture
  534.     structure to zero.                                                    */
  535.  
  536.     oldClip = NewRgn();
  537.     GetClip(oldClip);
  538.  
  539.     SetRect(&gPictsBounds, 0, 0, 150, 150);
  540.     ClipRect(&gPictsBounds);
  541.     
  542.     gPICTRec.numPICTs = 0;
  543.  
  544.  
  545. /*    Create a picture with a blue square in it.  We set the curPos
  546.     rectangle for all of these pictures to (0, 0, 0, 0) so that
  547.     we don't do any unnecessary erasing the first time they enter
  548.     MoveTheGroupies.                                                    */
  549.  
  550.     gPICTRec.picture[0] = OpenPicture(&gPictsBounds);
  551.     ForeColor(blueColor);
  552.     PaintRect(&gPictsBounds);
  553.     ClosePicture();
  554.     SetRect(&gPICTRec.curPos[0], 0, 0, 0, 0);
  555.     ++gPICTRec.numPICTs;
  556.  
  557.  
  558. /*    Create a picture with a red circle in it.                            */
  559.  
  560.     gPICTRec.picture[1] = OpenPicture(&gPictsBounds);
  561.     ForeColor(redColor);
  562.     PaintOval(&gPictsBounds);
  563.     ClosePicture();
  564.     SetRect(&gPICTRec.curPos[1], 0, 0, 0, 0);
  565.     ++gPICTRec.numPICTs;
  566.  
  567.  
  568. /*    Create a picture with a green triangle in it.    */
  569.  
  570.     gPICTRec.picture[2] = OpenPicture(&gPictsBounds);
  571.     ForeColor(greenColor);
  572.  
  573.     trianglePoly = OpenPoly();
  574.     MoveTo(gPictsBounds.left, gPictsBounds.bottom);
  575.     LineTo((gPictsBounds.right - gPictsBounds.left)/2, gPictsBounds.top);
  576.     LineTo(gPictsBounds.right, gPictsBounds.bottom);
  577.     LineTo(gPictsBounds.left, gPictsBounds.bottom);
  578.     ClosePoly();
  579.  
  580.     PaintPoly(trianglePoly);
  581.     KillPoly(trianglePoly);
  582.     ClosePicture();
  583.     SetRect(&gPICTRec.curPos[2], 0, 0, 0, 0);
  584.     ++gPICTRec.numPICTs;
  585.  
  586.  
  587. /*    Create a picture with some text in it.    */
  588.  
  589.     gPICTRec.picture[3] = OpenPicture(&gPictsBounds);
  590.     ForeColor(blackColor);
  591.  
  592.     GetFNum((ConstStr255Param) "\pTimes", (short*)&fNum);
  593.     TextFont(fNum);
  594.     TextSize(12);
  595.     TextFont(bold);
  596.     vPos = gPictsBounds.top +(gPictsBounds.bottom - gPictsBounds.top)/2;
  597.     MoveTo(gPictsBounds.left +10, vPos +10);
  598.     DrawString((ConstStr255Param) "\pCustom PicComments");
  599.     ClosePicture();
  600.     SetRect(&gPICTRec.curPos[3], 0, 0, 0, 0);
  601.     ++gPICTRec.numPICTs;
  602.  
  603.  
  604. /*    Restore the original clipping region.                                */
  605.  
  606.     SetClip(oldClip);
  607.     DisposeRgn(oldClip);
  608. }
  609.  
  610.  
  611. /*------ ShowThePicts ----------------------------------------------------------------*/
  612. //    ShowThePicts starts the show.
  613. //    First, we find the deepest display because the groupies are a colorful
  614. //    bunch.  Then we create a window and some pictures.  Finally, we jump into
  615. //    our main event loop.
  616. /*----------------------------------------------------------------------------------------*/
  617.  
  618. void ShowThePicts()
  619. {
  620.     Rect        maxRect, deepRect, wBounds;
  621.     GDHandle    deepGDH;
  622.  
  623. /*    Find the bounds of the deepest device.  We'll use this to determine
  624.     where to put our window.  Passing the maximum enclosing rectangle
  625.     to GetMaxDevice assures that we find the deepest device available.    */
  626.  
  627.     SetRect(&maxRect, -32767, -32767, 32767, 32767);
  628.     deepGDH = GetMaxDevice(&maxRect);
  629.     deepRect = (*deepGDH)->gdRect;
  630.  
  631.  
  632. /*    Create a window for our drawing, offset onto the deepest device.    */
  633.     
  634.     SetRect(&wBounds, 40, 40, 360, 340);
  635.     OffsetRect(&wBounds, wBounds.left +deepRect.left, wBounds.top +deepRect.top);
  636.  
  637.     gTheWindow = NewWindow(nil, &wBounds, (ConstStr255Param) "\pCustomPC/B", true, noGrowDocProc, (WindowPtr) -1, false, 1234);
  638.     //SetPort(gTheWindow);
  639.     SetPortWindowPort(gTheWindow);
  640.  
  641.  
  642. /*    Create our pictures to group, then go into the work loop.  This
  643.     loop continually groups the pictures, draws the grouped picture
  644.     in different locations, ungroups the picture, draws the ungrouped
  645.     pictures in different locations and repeats until the user quits.    */
  646.  
  647.     MakeThePicts();
  648.     EventLoop();
  649. }
  650.  
  651.  
  652. /*------ CompositePictures ----------------------------------------------------------------*/
  653. //    CompositePictures groups all of the pictures in the global picture record
  654. //    into one "composite" picture.  It removes all the old pictures and
  655. //    stores the new one.
  656. /*----------------------------------------------------------------------------------------*/
  657.  
  658. /*    -------------------------------------
  659.     main.
  660.     -------------------------------------    */
  661.  
  662. void main(void)
  663. {    
  664.     unsigned long randSeed;
  665.     Handle        menuBar;
  666.  
  667. /*    Initialize the toolbox routines.                                    */
  668.  
  669.     //InitGraf(&qd.thePort);
  670.     //InitFonts();
  671.     //InitWindows();
  672.     //InitMenus();
  673.     //InitDialogs(nil);
  674.     InitCursor();
  675.  
  676.  
  677. /*    Set up our menubar.                                                    */
  678.  
  679.     menuBar = GetNewMBar(rMenuBar);        /*    Read menus into menu bar    */
  680.     SetMenuBar(menuBar);                /*    and install them.            */
  681.     DisposeHandle(menuBar);
  682.     
  683.     //AppendResMenu(GetMenuHandle(mApple), 'DRVR');
  684.     DrawMenuBar();
  685.  
  686.  
  687. /*    Initialize the random number seed for our hopping groupies and set
  688.     our quitting flag to false.  Call the routine that runs everything,
  689.     then, quit.                                                            */
  690.  
  691.     GetDateTime(&randSeed);
  692.     gQuitting = false;
  693.     ShowThePicts();
  694. }
  695.